/*
 * Change Logs:
 * Date           Author       Notes
 * 2022-03-27     chenbin
 */
#include "fdown.h"
#if (FBOOT_USING_FDOWN == 1)

#define DBG_ENABLE
#define DBG_SECTION_NAME "fdown"
#define DBG_LEVEL DBG_INFO
#include <rtdbg.h>

#if (FDOWN_USING_HTTP == 1)

#include "webclient.h"
#include <fal.h>

#define HTTP_READ_BUFFER_SIZE      4096U
#define HTTP_HEADER_BUFFER_SIZE    4096U

int fdown_http2fal(const char * http_url, const char * fal_part_name)
{
	int ret = 0;
	int file_size = 0;
	int read_rc = 0;
	int write_rc = 0;
	rt_size_t read_len = 0;
	rt_size_t write_pos = 0;
	rt_size_t write_total = 0;
	
	rt_uint8_t *rw_buffer = RT_NULL;
	struct webclient_session *session = RT_NULL;
	const struct fal_partition *dl_part = RT_NULL;
	
	uint32_t tick_start,tick_end;

	LOG_I("%s(\"%s\",\"%s\");", __FUNCTION__, http_url, fal_part_name);

	if (http_url == NULL)
	{
			LOG_E("url is NULL");
			ret = -RT_ERROR;
			goto __exit;
	}
	/* Get download partition information and erase download partition data */
	dl_part = fal_partition_find(fal_part_name);
	if (dl_part == RT_NULL)
	{
			LOG_E("fal partition (%s) is not exist!", fal_part_name);
			ret = -RT_ERROR;
			goto __exit;
	}
	LOG_I("fal erase len: 0x%08x", dl_part->len);
	ret = fal_partition_erase(dl_part, 0, dl_part->len);
	if (ret < 0)
	{
			LOG_E("fal erase faild rc:%d", ret);
			goto __exit;
	}
	session = webclient_session_create(HTTP_HEADER_BUFFER_SIZE);
	if (!session)
	{
			LOG_E("create webclient session failed.");
			ret = -RT_ERROR;
			goto __exit;
	}
	/* send GET request by default header */
	ret = webclient_get(session, http_url);
	if (ret != 200)
	{
			LOG_E("webclient GET request failed, response(%d) error.", ret);
			ret = -RT_ERROR;
			goto __exit;
	}
	file_size = webclient_content_length_get(session);
	if (file_size == 0)
	{
			LOG_E("Request file size is 0!");
			ret = -RT_ERROR;
			goto __exit;
	}
	else if (file_size < 0)
	{
			LOG_E("webclient GET request type is chunked.");
			ret = -RT_ERROR;
			goto __exit;
	}
	rw_buffer = web_malloc(HTTP_READ_BUFFER_SIZE);
	if (rw_buffer == RT_NULL)
	{
			LOG_E("No memory for http ota!");
			ret = -RT_ERROR;
			goto __exit;
	}
	memset(rw_buffer, 0x00, HTTP_READ_BUFFER_SIZE);
	
	LOG_I("http download size (%d)", file_size);
	write_pos = 0;
	write_total = file_size;
	if(write_total > dl_part->len)
	{
		write_total = dl_part->len;
	}
	LOG_I("download start.");
	tick_start = rt_tick_get();
	LOG_RAW("download < %02d%% >", write_pos * 100 / write_total);
	while (write_pos < write_total)
	{
			read_len = HTTP_READ_BUFFER_SIZE;
			if (read_len > (write_total - write_pos))
			{
					read_len = (write_total - write_pos);
			}
			read_rc = webclient_read(session, rw_buffer, read_len);
			if (read_rc < 0)
			{
					LOG_E("http server return err (%d)!", read_rc);
					ret = read_rc;
					goto __exit;
			}
			write_rc = fal_partition_write(dl_part, write_pos , rw_buffer, read_rc);
			if (write_rc <= 0)
			{
					LOG_E("fal write faild rc:%d  pos:%d len:%d", write_rc, (write_pos), read_rc);
					ret = write_rc;
					goto __exit;
			}
			write_pos += write_rc;
			LOG_RAW("\r\033[K");
			LOG_RAW("download < %02d%% >", write_pos * 100 / write_total);
	}
	LOG_RAW("\r\033[K");
	LOG_RAW("download < %02d%% >\n", write_pos * 100 / write_total);
	LOG_I("download %08d / %08d bytes.", write_pos, write_total);
	tick_end = rt_tick_get();
	read_rc = ((write_pos * 1000U) /(tick_end - tick_start));
	LOG_I("download used: %d ms, speed: %d bytes/s ",(tick_end - tick_start), read_rc );
	LOG_I("download end.");
	ret = write_pos;
	
__exit:
	if (session != RT_NULL)
			webclient_close(session);
	if (rw_buffer != RT_NULL)
			web_free(rw_buffer);

	return ret;
}


#if (FBOOT_USING_FILESYSTEM == 1)

#ifdef RT_USING_DFS
#include <dfs.h>
#include <dfs_fs.h>
#include <dfs_file.h>
#endif

#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/time.h>
#include <sys/ioctl.h>

int fdown_http2fs(const char *http_url, const char *file_name)
{
	int ret = 0;
	int file_size = 0;
	int read_rc = 0;
	int write_rc = 0;
	rt_size_t read_len = 0;
	rt_size_t write_pos = 0;
	rt_size_t write_total = 0;
	
	rt_uint8_t *rw_buffer = RT_NULL;
	struct webclient_session *session = RT_NULL;
	
	int fd = 0;
	
	uint32_t tick_start,tick_end;

	LOG_I("%s(\"%s\",\"%s\");", __FUNCTION__, http_url, file_name);

	if (http_url == NULL)
	{
			LOG_E("url is NULL");
			ret = -RT_ERROR;
			goto __exit;
	}
	/* create webclient session and set header response size */
	session = webclient_session_create(HTTP_HEADER_BUFFER_SIZE);
	if (!session)
	{
			LOG_E("create webclient session failed.");
			ret = -RT_ERROR;
			goto __exit;
	}
	/* send GET request by default header */
	ret = webclient_get(session, http_url);
	if (ret != 200)
	{
			LOG_E("webclient GET request failed, response(%d) error.", ret);
			ret = -RT_ERROR;
			goto __exit;
	}
	file_size = webclient_content_length_get(session);
	if (file_size == 0)
	{
			LOG_E("Request file size is 0!");
			ret = -RT_ERROR;
			goto __exit;
	}
	else if (file_size < 0)
	{
			LOG_E("webclient GET request type is chunked.");
			ret = -RT_ERROR;
			goto __exit;
	}
	fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0);
	if (fd < 0)
	{
			LOG_E("get file failed, open file(%s) error.", file_name);
			ret = -WEBCLIENT_ERROR;
			goto __exit;
	}
	rw_buffer = web_malloc(HTTP_READ_BUFFER_SIZE);
	if (rw_buffer == RT_NULL)
	{
			LOG_E("No memory for http ota!");
			ret = -RT_ERROR;
			goto __exit;
	}
	rt_memset(rw_buffer, 0x00, HTTP_READ_BUFFER_SIZE);
	
	LOG_I("http download size (%d)", file_size);
	write_total = file_size;
	write_pos = 0;
	
	LOG_I("download start.");
	tick_start = rt_tick_get();
	LOG_RAW("download < %02d%% >", write_pos * 100 / write_total);
	while (write_pos < write_total)
	{
			read_len = HTTP_READ_BUFFER_SIZE;
			if (read_len > (write_total - write_pos))
			{
					read_len = (write_total - write_pos);
			}
			read_rc = webclient_read(session, rw_buffer, read_len);
			if (read_rc < 0)
			{
					LOG_E("http server return err (%d)!", read_rc);
					ret = read_rc;
					goto __exit;
			}
			write_rc = write(fd, rw_buffer, read_rc);
			if (write_rc <= 0)
			{
					LOG_E("write faild rc:%d  pos:%d len:%d", write_rc, (write_pos), read_rc);
					ret = write_rc;
					break;
			}
			write_pos += write_rc;
			LOG_RAW("\r\033[K");
			LOG_RAW("download < %02d%% >", write_pos * 100 / write_total);
	}
	LOG_RAW("\r\033[K");
	LOG_RAW("download < %02d%% >\n", write_pos * 100 / write_total);
	LOG_I("download %08d / %08d bytes.", write_pos, write_total);
	tick_end = rt_tick_get();
	read_rc = ((write_total * 1000U) /(tick_end - tick_start));
	LOG_I("download used: %d ms , average speed: %d bytes/s ",(tick_end - tick_start), read_rc );
	LOG_I("download end.");
	ret = write_pos;

__exit:
	if (fd >= 0)
	{
		close(fd);
	}
	if (session != RT_NULL)
	{
		webclient_close(session);
	}
	if (rw_buffer != RT_NULL)
	{
		web_free(rw_buffer);
	}
	return ret;
}

#endif /* FBOOT_USING_FILESYSTEM */



#endif /* FDOWN_USING_HTTP */

#endif /* FBOOT_USING_FDOWN */
